﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HandleClient
{
    public class TcpPacketClient
    {
        private TcpClient _client;
        private NetworkStream _stream;
        private readonly CancellationTokenSource _cts = new CancellationTokenSource();

        public void Connect(string serverIp, int port)
        {
            _client = new TcpClient();
            _client.Connect(serverIp, port);
            _stream = _client.GetStream();
            Console.WriteLine($"Connected to {serverIp}:{port}");

            // 启动接收线程
            _ = ReceiveDataAsync();
        }

        private async System.Threading.Tasks.Task ReceiveDataAsync()
        {
            var buffer = new byte[4096];
            var receiveBuffer = new List<byte>();

            try
            {
                while (_client.Connected && !_cts.IsCancellationRequested)
                {
                    var bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length, _cts.Token);
                    if (bytesRead == 0) break;

                    receiveBuffer.AddRange(new ArraySegment<byte>(buffer,0, bytesRead));

                    // 解析所有完整数据包
                    while (TryParsePacket(receiveBuffer.ToArray(), out var packet, out int packetSize))
                    {
                        ProcessPacket(packet);
                        receiveBuffer.RemoveRange(0, packetSize);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Connection error: {ex.Message}");
            }
            finally
            {
                Disconnect();
            }
        }

        public void SendPacket(byte command, string message)
        {
            var packet = new TcpPacket
            {
                Command = command,
                Data = Encoding.UTF8.GetBytes(message)
            };
            SendPacket(packet);
        }

        private async void SendPacket(TcpPacket packet)
        {
            try
            {
                byte[] data = packet.Serialize();
                await _stream.WriteAsync(data, 0, data.Length, _cts.Token);
                Console.WriteLine($"Sent command 0x{packet.Command:X2}, data: {Encoding.UTF8.GetString(packet.Data)}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Send error: {ex.Message}");
            }
        }

        private bool TryParsePacket(byte[] buffer, out TcpPacket packet, out int packetSize)
        {
            packet = null;
            packetSize = 0;

            // 最小包长度检查
            if (buffer.Length < 9) return false;

            // 查找包头
            int startIndex = FindHeaderIndex(buffer);
            if (startIndex == -1) return false;

            // 提取数据长度（大端序）
            byte[] lengthBytes = new byte[4];
            Array.Copy(buffer, startIndex + 2, lengthBytes, 0, 4);
            if (BitConverter.IsLittleEndian) Array.Reverse(lengthBytes);
            uint dataLength = BitConverter.ToUInt32(lengthBytes, 0);

            // 计算完整包长度
            int totalLength = startIndex + 9 + (int)dataLength;
            if (buffer.Length < totalLength) return false;

            // 验证包尾
            byte[] footer = new byte[2];
            Array.Copy(buffer, totalLength - 2, footer, 0, 2);
            if (!footer.SequenceEqual(TcpPacket.Footer)) return false;

            // 提取有效数据
            byte[] packetData = new byte[totalLength - startIndex];
            Array.Copy(buffer, startIndex, packetData, 0, packetData.Length);

            try
            {
                packet = TcpPacket.Deserialize(packetData);
                packetSize = packetData.Length;
                return true;
            }
            catch
            {
                return false;
            }
        }

        private int FindHeaderIndex(byte[] buffer)
        {
            for (int i = 0; i <= buffer.Length - 2; i++)
            {
                if (buffer[i] == 0xFF && buffer[i + 1] == 0xFF)
                {
                    return i;
                }
            }
            return -1;
        }

        private void ProcessPacket(TcpPacket packet)
        {
            Console.WriteLine($"Received response [0x{packet.Command:X2}]: {Encoding.UTF8.GetString(packet.Data)}");
        }

        public void Disconnect()
        {
            _cts.Cancel();
            _client?.Close();
            Console.WriteLine("Disconnected from server");
        }
    }
}
